# -*- coding: utf-8 -*-

from itertools import chain
import threading
from typing import Any, Callable, List
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
from contract_market.base.event import Event
from .actor import Actors


class EventCenter(Actors):
    """ """

    def __init__(self, maxsize: int = 100) -> None:
        """ """
        super().__init__(maxsize=maxsize)
        self._handles: defaultdict = defaultdict(list)
        self._general_handles: List = []

        self._handle_lock = threading.Lock()
        self._handle_cond = threading.Condition(self._handle_lock)

        self._general_lock = threading.Lock()
        self._general_cond = threading.Condition(self._general_lock)
        self._pool = ThreadPoolExecutor(max_workers=100)  # TODO

    def register(self, event_type: str, handle: Callable[[Any], Any]):
        """ """
        with self._handle_lock:
            self._handles[event_type].append(handle)

    def unregister(self, event_type: str, handle: Callable[[Any], Any]):
        """ """
        with self._handle_lock:
            if event_type not in self._handles:
                return
            handles_len = len(self._handles[event_type])
            if not handles_len:
                self._handles.pop(event_type)
            else:
                self._handles[event_type].remove(handle)

    def attach(self, handle: Callable[[Any], Any]):
        """ """
        with self._general_cond:
            self._general_handles.append(handle)

    def detach(self, handle: Callable[[Any], Any]):
        """ """
        with self._general_cond:
            handle_len = len(self._general_handles)
            if not handle_len:
                return
            self._general_handles.remove(handle)

    def handles(self):
        """ """
        return self._general_handles

    def obtain_events(self, event_type: str = None):
        """ """
        if not event_type:
            return self._handles
        else:
            return self._handles[event_type]

    def execut(self, event: Event):
        """ """
        handles = self._handles.get(event.event_type, [])
        for handle in chain(handles, self._general_handles):
            self._pool.submit(handle, event.event_data)
            # handle(event.event_data)

    def run(self):
        """ """
        event = super().run()
        # print("[EventCenter-run-event] ", event)
        self.execut(event)

    def send(self, event):
        """ """
        super().send(event)
